#include "tutorialSelection.hxx"
#include "baseSelection.hxx"
#include "CutUtils.hxx"
#include "SubDetId.hxx"

//********************************************************************
tutorialSelection::tutorialSelection(bool forceBreak): SelectionBase(forceBreak) {
//********************************************************************
    // Define the steps
    DefineSteps();
}

//********************************************************************
void tutorialSelection::DefineSteps(){
//********************************************************************

    // Cuts must be added in the right order
    // last "true" means the step sequence is broken if cut is not passed (default is "false")
    AddStep(StepBase::kCut,    "event quality",      new EventQualityCut(),           true);
    AddStep(StepBase::kCut,    "> 0 tracks ",        new TotalMultiplicityCut(),      true);  
    AddStep(StepBase::kAction, "find leading tracks",new FindLeadingTracksAction());  
    AddStep(StepBase::kAction, "find vertex",        new FindVertexAction());  
    AddStep(StepBase::kAction, "fill_summary",       new FillSummaryAction_tutorial());
    AddStep(StepBase::kCut,    "quality+fiducial",   new TrackQualityFiducialCut(),   true);  
    AddStep(StepBase::kAction, "find veto track",    new FindVetoTrackAction());
    AddStep(StepBase::kCut,    "veto",               new ExternalVetoCut());
    AddStep(StepBase::kAction, "find oofv track",    new FindOOFVTrackAction());
    AddStep(StepBase::kCut,    "External FGD1",      new ExternalFGD1lastlayersCut());
    AddStep(StepBase::kCut,    "muon PID",           new MuonPIDCut());

    // This is mandatory. An alias should be given to each of the branches
    SetBranchAlias(0,"trunk");
}

//********************************************************************
bool tutorialSelection::FillEventSummary(const AnaBoxB& box, AnaEventB& event, Int_t allCutsPassed[]){
//********************************************************************

    (void)box;
    if(allCutsPassed[0]){
        event.Summary->EventSample = nd280Samples::kFGD1NuMuCC;
    }
    return (event.Summary->EventSample != nd280Samples::kUnassigned);
}

//**************************************************
bool TotalMultiplicityCut::Apply(const AnaEventB& event, AnaBoxB& box) const{
//**************************************************

    (void)box;

    // 1. Multiplicity
    // Check we have at least one reconstructed track in the TPC
    if (anaUtils::HasTrackUsingTPC(event))
       return true;
    else
        return false;
}

//**************************************************
bool TrackQualityFiducialCut::Apply(const AnaEventB& event, AnaBoxB& box) const{
//**************************************************

    (void)event;

    if (box.Vertex)
        return true;
    else 
        return false;
}

//**************************************************
bool MuonPIDCut::Apply(const AnaEventB& event, AnaBoxB& box) const{
//**************************************************

    (void)event;

    if (!box.HMNtrack)
        return false;
    if (box.HMNtrack->Momentum < 0.) return false;
    return cutUtils::MuonPIDCut(*(box.HMNtrack), _prod5Cut);
}

//********************************************************************
bool ExternalVetoCut::Apply(const AnaEventB& event, AnaBoxB& box) const{
//********************************************************************

    (void)event;

    if (!box.HMNtrack)
        return false;
    return cutUtils::ExternalVetoCut(*(box.HMNtrack),box.VetoTrack);
}

//********************************************************************
bool DeltaZCut::Apply(const AnaEventB& event, AnaBoxB& box) const{
//********************************************************************

    (void)event;

    if (!box.HMNtrack)
        return false;
    return cutUtils::DeltaZCut(*(box.HMNtrack));
}

//********************************************************************
bool ExternalFGD1lastlayersCut::Apply(const AnaEventB& event, AnaBoxB& box) const{
//********************************************************************

    (void)event;

    /// Reject external background from the last 2 layers of FGD1
    if (!box.HMNtrack)
        return false;  
    if (box.OOFV && (box.HMNtrack->PositionStart[2]>425.))
        return false;
    return true; 
}

//**************************************************
bool FindVertexAction::Apply(const AnaEventB& event, AnaBoxB& box) const{
//**************************************************

    (void)event;

    // reset the vertex 
    box.Vertex = NULL;

    if (!box.HMNtrack) return false;

    box.Vertex = new AnaVertexB();
    utils::CreateArray(box.Vertex->Tracks, 1);

    box.Vertex->nTracks = 0;
    box.Vertex->Tracks[box.Vertex->nTracks++] = box.HMNtrack;

    for(int i = 0; i < 4; ++i){
        box.Vertex->Position[i] = box.HMNtrack->PositionStart[i];
    }
    if(  box.HMNtrack->TrueTrack ) 
        box.Vertex->TrueVertex = box.HMNtrack->TrueTrack->TrueVertex;
    return true;
}

//********************************************************************
bool FillSummaryAction_tutorial::Apply(const AnaEventB& event, AnaBoxB& box) const{
//********************************************************************
    if(!box.HMNtrack) return 1;

    event.Summary->LeptonCandidate[nd280Samples::kFGD1NuMuCC] = box.HMNtrack;
    for(int i = 0; i < 4; ++i){
        event.Summary->VertexPosition[nd280Samples::kFGD1NuMuCC][i] = box.HMNtrack->PositionStart[i];
    }
    if(box.HMNtrack->TrueTrack) event.Summary->TrueVertex[nd280Samples::kFGD1NuMuCC] = box.HMNtrack->TrueTrack->TrueVertex;
    return 1;
}

//**************************************************
bool FindLeadingTracksAction::Apply(const AnaEventB& event, AnaBoxB& box) const{
//**************************************************
    // Find leading tracks with good quality and only in FGD1 FV
    bool applyQualityCut=true;
    cutUtils::FindLeadingTracks(event, box, applyQualityCut, SubDetId::kFGD1);
    return true;
}

//**************************************************
bool FindVetoTrackAction::Apply(const AnaEventB& event, AnaBoxB& box) const{
//**************************************************

    box.VetoTrack = cutUtils::FindVetoTrack(event, *(box.HMNtrack));  
    return true;
}

//**************************************************
bool FindOOFVTrackAction::Apply(const AnaEventB& event, AnaBoxB& box) const{
//**************************************************

    cutUtils::FindFGD1OOFVtrack(event, box);
    return true;
}
